package com.ruoyi.aitncc.service;

import java.io.File;
import java.util.*;

import com.alibaba.fastjson.JSON;
import com.ruoyi.aitcommon.config.AITConfig;
import com.ruoyi.aitcommon.utils.*;
import com.ruoyi.aitcommon.vo.AttachmentVO;
import com.ruoyi.common.core.redis.RedisCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.aitcommon.anotation.ServiceLog;
import com.ruoyi.aitcommon.service.IAitEntityInfoService;
import com.ruoyi.aitcommon.vo.AggMap;
import com.ruoyi.aitcommon.vo.AggVO;
import com.ruoyi.aitncc.vo.NCContextVO;
import com.ruoyi.aitncc.vo.NCParmVO;
import com.ruoyi.common.constant.HttpStatus;

@Service
public class NCCRestService {
	@Autowired
	IAitEntityInfoService infoService;
	@Autowired
	EntityCache entityCache;
	@Autowired
	RedisCache redisCache;
	
	@ServiceLog("NCC rest调用")
	public JSONObject restInvoke(JSONObject context, String url, Object data) throws Exception {
		if (data == null) {
			return JSONResult.success("没有数据");
		}

		// 转换context为VO
		NCContextVO contextVO = JSONObject.toJavaObject(context, NCContextVO.class);
		// 装配ncc json
		NCParmVO parmvo = new NCParmVO();
		parmvo.context = contextVO;
		parmvo.data = data;
		// 调用ncc服务
		JSONObject json = (JSONObject)JSONObject.toJSON(parmvo);
		JSONObject retjson = RestServiceUtils.post(url,null,json);
		// 处理ncc服务返回
		JSONResult.jsonAssert(retjson);
		return retjson;
	}

	@ServiceLog("NCC 档案保存")
	public List<JSONObject> entitySave(JSONObject context, String url, List<Map<String, Object>> datas,
			JSONObject entityInfo) throws Exception {
		List<JSONObject> retlist=new ArrayList<JSONObject>();
		
		ExceptionUtils.checkBlankOrUndefined(context, "context为空");
		ExceptionUtils.checkBlankOrUndefined(url, "url为空");
		ExceptionUtils.checkBlankOrUndefined(entityInfo, "entityInfo为空");
		
		//从缓存过滤重复数据
		List<Map<String,Object>> filterlist = entityCache.filterEntityChange(entityInfo, datas);
				 
		for (Map<String, Object> data : filterlist) {
//			循环单条处理
			try {
//				依据data动态构造context
//				动态特性,需要在flow中,将context放入extinfo中
				Map<String, Object> context1 = FlowParamUtils.getFlowParamsValue(context, data);
//				调用 ncc 接口
				JSONObject retjson=restInvoke(new JSONObject(context1), url, Arrays.asList(data));
				if(entityInfo!=null) {
//					处理实体日志和缓存
					if(!entityInfo.containsKey("oper"))
						entityInfo.put("oper", "保存");
					infoService.insertAitEntityInfo(entityInfo, data, null);
				}
				retlist.add(retjson);
			}catch(Exception ex) {
//				ex.printStackTrace();
//				处理实体日志和缓存-失败信息
				infoService.insertAitEntityInfo(entityInfo, data, ex);
				//文件错误日志
				JSONObject retjson=JSONResult.error(ex.getMessage());
				retlist.add(retjson);
			}
		}
		return retlist;
	}
	
	@ServiceLog("NCC 单据保存")
	public List<JSONObject> docSave(JSONObject context, String url, List<AggMap> datas,
			JSONObject entityInfo) throws Exception {
		List<JSONObject> retlist=new ArrayList<JSONObject>();
		
		ExceptionUtils.checkBlankOrUndefined(context, "context为空");
		ExceptionUtils.checkBlankOrUndefined(url, "url为空");
		ExceptionUtils.checkBlankOrUndefined(entityInfo, "entityInfo为空");
		
		//从缓存过滤重复数据
		List<Map<String,Object>> filterlist = entityCache.filterEntityChange(entityInfo, ListMapUtils.agg2Map(datas));
					
		for (Map<String,Object> data : filterlist) {
			try {
//				依据data动态构造context
//				动态特性,需要在flow中,将context放入extinfo中
				Map<String, Object> context1 = FlowParamUtils.getFlowParamsValue(context, data);
//				将data转为doc,调用服务
				AggMap agg=new AggMap(data);
				JSONObject doc = new JSONObject();
				doc.put("doc", agg.getHeadVO());
				doc.put("lines", agg.getBodyVOS());
				JSONObject retjson=restInvoke(new JSONObject(context1), url, Arrays.asList(doc));
				if(entityInfo!=null) {
					entityInfo.put("oper", "保存");
					infoService.insertAitEntityInfo(entityInfo, agg, null);
				}
				retlist.add(retjson);
			}catch(Exception ex) {
//				ex.printStackTrace();
//				处理实体日志和缓存-失败信息
				infoService.insertAitEntityInfo(entityInfo, data, ex);
//				处理返回
				retlist.add(JSONResult.error(ex.getMessage()));
			}
		}
		return retlist;
	}

	/**
	 * 调用NCC通用查询接口
	 * @param context
	 * @param url
	 * @param data
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	@ServiceLog("NCC 单据查询")
	public List<AggMap> docQuery(JSONObject context, String url, JSONObject data) throws Exception {
		List<AggMap> retlist = new ArrayList();
		String dockey = data.getString("dockey");
		String table = data.getString("table");
		String docsql = data.getString("docsql");
		String subtable = data.getString("subtable");
		String linesql = data.getString("linesql");

		JSONObject data1 = new JSONObject();
		data1.put("tablename", table);
		data1.put("sql", docsql);
		JSONObject retjson1 = restInvoke(context, url, data1);
		JSONArray doclist = retjson1.getJSONArray("data");
		for (Object doc : doclist) {

			Map<String, Object> docmap = (Map<String, Object>) doc;
			AggMap agg = new AggMap(docmap);
			Object id = docmap.get(dockey);
			if (id != null) {
				String sql = String.format(linesql, id.toString());
				JSONObject data2 = new JSONObject();
				data2.put("tablename", subtable);
				data2.put("sql", sql);
				JSONObject retjson2 = restInvoke(context, url, data2);
				JSONArray linelist = retjson2.getJSONArray("data");
				List<Map<String, Object>> bodys = new ArrayList<Map<String, Object>>();
				for (Object line : linelist) {
					bodys.add((Map<String, Object>) line);
				}
				agg.setBodyVOS(bodys);
			}
			retlist.add(agg);
		}
		return retlist;
	}

	/**
	 * NCC附件处理流程,思路如下:
	 * 调用NCC附件保存接口
	 * 将NCC附件存入本地
	 * 将NCC附件信息存储redis
	 * @param context
	 * @param url
	 * @param datas
	 * @param entityInfo
	 * @param parms
	 * @return
	 * @throws Exception
	 */
	@ServiceLog("NC单据附件处理")
	public List<AggMap> docAttachment(JSONObject context,String url,List<AggMap> datas
			,JSONObject entityInfo,Map<String,Object> parms) throws Exception {
		JSONObject parmsjson=new JSONObject(parms);
		final String entityName = parmsjson.getString("entityName");
		ObjUtils.checkBlank(entityName,"parms中必须包含entityName");
		final String codeField = parmsjson.getString("codeField");
		ObjUtils.checkBlank(codeField,"parms中必须包含codeField");
		final String fileUrl = parmsjson.getString("fileUrl");
		ObjUtils.checkBlank(fileUrl,"parms中必须包含fileUrl");
		final String redisKey = parmsjson.getString("redisKey");
		ObjUtils.checkBlank(fileUrl,"parms中必须包含redisKey");

		for(AggMap data:datas){
			//循环每条数据,调用NC附件保存接口
			final Object code = data.getHeadVO().get(codeField);
			ObjUtils.checkBlank(code,"数据中不存在[%s],或值为空",codeField);

			//调用NC保存服务
			Map<String,Object> query=new LinkedHashMap<>();
			query.put("tablename",entityName);
			query.put("docno",code);
			query.put("ts",new Date());//强制调用接口,调试用
			final List<JSONObject> attlist = this.entitySave(context, url, ObjUtils.toList(query), entityInfo);

			//返回附件处理
			if(ObjUtils.isNotBlank(attlist)){
				final JSONArray retlist = attlist.get(0).getJSONArray("data");
				if(ObjUtils.isNotBlank(retlist)){
					List<AttachmentVO> atts=new ArrayList<>();
					for (Object attobj : retlist) {
						JSONObject attjson=(JSONObject) attobj;
						AttachmentVO attvo=new AttachmentVO();
						attvo.setDocName(entityName);
						attvo.setDocNo(attjson.getString("docno"));
						attvo.setFileUrl(fileUrl+attjson.getString("filepath1"));
						attvo.setFileName(attjson.getString("filename"));
						//下载附件,存储在本地
						String path= AITConfig.getUploadPath()+"\\"+attvo.getDocName()+"\\"+attvo.getDocNo()+"\\"+attvo.getFileName();
						final File file = RestServiceUtils.getFile(attvo.getFileUrl(), path);
						attvo.setFilePath(file.getAbsolutePath());

						atts.add(attvo);
					}
					//将返回数据按照 tablename+docno,存入redis
					String key=redisKey+":"+entityName+":"+code;
					redisCache.setCacheObject(key,atts);
				}
			}
		}
		return datas;
	}
}
